package com.atguigu.gmall.order.listener.mq;

import com.atguigu.gmall.feign.pay.PayFeignClient;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.MqConst;
import com.atguigu.gmall.mq.RabbitConst;
import com.atguigu.gmall.mq.to.WareStockedRespTo;
import com.atguigu.gmall.order.service.OrderService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;

/**
 * 随便开发业务的技巧：
 * 1、application.yaml 配置 spring.rabbit下的所有
 * 2、发送消息 自动注入 RabbitTemplate ，
 * 调用 RabbitTemplate.converAndSend(交换机，路由键)
 * 3、监听消息 @RabbitListener 标在方法上
 * Message message, Channel channel,<?> 自己的数据类型
 * 手工确认模式
 *          try{
 *          业务
 *          channel.basicAck()
 *          }catch(e){
 *          channel.basicNack();
 *          }
 */
@Slf4j
@Service
public class OrderMessageConsumer {

    @Autowired
    OrderService orderService;

    @Autowired
    PayFeignClient payFeignClient;


    /**
     * 库存系统扣减完库存，无论是否成功，都会给queue.ware.order发送消息 {orderId:xxxx,status:xxxx}
     *
     * 交换机：MqConst.EXCHANGE_DIRECT_WARE_ORDER
     * 路由键： MqConst.ROUTING_WARE_ORDER
     * 队列：queue.ware.order
     *
     * this.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_ORDER, MqConst.ROUTING_WARE_ORDER, JSON.toJSONString(map));
     * @param message
     * @param channel
     * @param wareJson
     */
    //@RabbitListener(queues = "queue.ware.order")
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_WARE_ORDER,durable = "true",exclusive = "false",autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_WARE_ORDER,durable = "true",type = ExchangeTypes.TOPIC,autoDelete = "false"),
                    key = MqConst.ROUTING_WARE_ORDER

            )
    })//监听 @Queue这个队列
    public void listenWareStock(Message message,Channel channel,String wareJson) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            WareStockedRespTo wareStockedRespTo = new ObjectMapper().readValue(wareJson, WareStockedRespTo.class);

            //修改订单状态
            String orderId = wareStockedRespTo.getOrderId();
            String status = wareStockedRespTo.getStatus();
            if ("DEDUCTED".equals(status)){
                //库存扣减成功
                orderService.changeOrderStatus(Long.parseLong(orderId), OrderStatus.WAITING_DELEVER);
            }else {
                //库存扣减失败
                orderService.changeOrderStatus(Long.parseLong(orderId), OrderStatus.WAITING_SCHEDULED);
                //补偿业务，给补货系统发消息，通知其补货
            }

            channel.basicAck(deliveryTag,false);
        } catch (JsonProcessingException e) {
            channel.basicNack(deliveryTag,false,true);
        }

    }

    /**
     * Message message: 代表消息
     * Channel channel： 消息的通道
     * 上次没有处理完的，mq不会把消息继续交给我们
     *
     * @param message
     * @param channel
     * @param orderId
     */
    @RabbitListener(queues = RabbitConst.ORDER_RELEASE_QUEUE)//死信队列
    public void closeOrder(Message message, Channel channel, Long orderId) throws IOException {
        System.out.println("收到释放订单的消息：" + orderId);
        //获取到mq给我们发来的消息的属性
        MessageProperties messageProperties = message.getMessageProperties();
        long deliveryTag = messageProperties.getDeliveryTag();
        //redelivered 是true，说明消息是重新发来的
        Boolean redelivered = messageProperties.getRedelivered();
        //关单处理
        try {
            //TODO 查询此交易是否支付 out_trade_no 订单交易号
            OrderInfo byId = orderService.getById(orderId);
            String outTradeNo = byId.getOutTradeNo();
            //远程查询支付宝，该订单是否关闭
            String s = payFeignClient.queryOrderPayStatus(outTradeNo);
            if ("0".equals(s)){
                log.info("{}：订单关单完成",orderId);
                orderService.closeOrder(orderId);
            }

            //幂等性
/*            if (redelivered) {
                log.info("由于系统原因，{}订单关单消息，重复投递进来",orderId);
            }else {

            }*/

            channel.basicAck(deliveryTag, false);//回复消息已经处理
        } catch (Exception e) {
            channel.basicNack(deliveryTag,false,true);
            e.printStackTrace();
        }
    }
}
